~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2010-04-01 04:41:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5128.
  • Revision ID: mbp@sourcefrog.net-20100401044118-shyctqc02ob08ngz
ignore .testrepository

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import difflib
18
18
import os
19
19
import re
 
20
import shutil
20
21
import string
21
22
import sys
22
23
 
31
32
    branch as _mod_branch,
32
33
    bzrdir,
33
34
    cmdline,
34
 
    cleanup,
35
35
    errors,
36
36
    osutils,
37
37
    patiencediff,
43
43
from bzrlib.workingtree import WorkingTree
44
44
""")
45
45
 
46
 
from bzrlib.registry import (
47
 
    Registry,
48
 
    )
49
46
from bzrlib.symbol_versioning import (
50
47
    deprecated_function,
51
 
    deprecated_in,
52
48
    )
53
49
from bzrlib.trace import mutter, note, warning
54
50
 
99
95
    if sequence_matcher is None:
100
96
        sequence_matcher = patiencediff.PatienceSequenceMatcher
101
97
    ud = patiencediff.unified_diff(oldlines, newlines,
102
 
                      fromfile=old_filename.encode(path_encoding, 'replace'),
103
 
                      tofile=new_filename.encode(path_encoding, 'replace'),
 
98
                      fromfile=old_filename.encode(path_encoding),
 
99
                      tofile=new_filename.encode(path_encoding),
104
100
                      sequencematcher=sequence_matcher)
105
101
 
106
102
    ud = list(ud)
290
286
                        new_abspath, e)
291
287
 
292
288
 
293
 
@deprecated_function(deprecated_in((2, 2, 0)))
294
289
def get_trees_and_branches_to_diff(path_list, revision_specs, old_url, new_url,
295
290
                                   apply_view=True):
296
291
    """Get the trees and specific files to diff given a list of paths.
315
310
    :returns:
316
311
        a tuple of (old_tree, new_tree, old_branch, new_branch,
317
312
        specific_files, extra_trees) where extra_trees is a sequence of
318
 
        additional trees to search in for file-ids.  The trees and branches
319
 
        are not locked.
320
 
    """
321
 
    op = cleanup.OperationWithCleanups(get_trees_and_branches_to_diff_locked)
322
 
    return op.run_simple(path_list, revision_specs, old_url, new_url,
323
 
            op.add_cleanup, apply_view=apply_view)
324
 
    
325
 
 
326
 
def get_trees_and_branches_to_diff_locked(
327
 
    path_list, revision_specs, old_url, new_url, add_cleanup, apply_view=True):
328
 
    """Get the trees and specific files to diff given a list of paths.
329
 
 
330
 
    This method works out the trees to be diff'ed and the files of
331
 
    interest within those trees.
332
 
 
333
 
    :param path_list:
334
 
        the list of arguments passed to the diff command
335
 
    :param revision_specs:
336
 
        Zero, one or two RevisionSpecs from the diff command line,
337
 
        saying what revisions to compare.
338
 
    :param old_url:
339
 
        The url of the old branch or tree. If None, the tree to use is
340
 
        taken from the first path, if any, or the current working tree.
341
 
    :param new_url:
342
 
        The url of the new branch or tree. If None, the tree to use is
343
 
        taken from the first path, if any, or the current working tree.
344
 
    :param add_cleanup:
345
 
        a callable like Command.add_cleanup.  get_trees_and_branches_to_diff
346
 
        will register cleanups that must be run to unlock the trees, etc.
347
 
    :param apply_view:
348
 
        if True and a view is set, apply the view or check that the paths
349
 
        are within it
350
 
    :returns:
351
 
        a tuple of (old_tree, new_tree, old_branch, new_branch,
352
 
        specific_files, extra_trees) where extra_trees is a sequence of
353
 
        additional trees to search in for file-ids.  The trees and branches
354
 
        will be read-locked until the cleanups registered via the add_cleanup
355
 
        param are run.
 
313
        additional trees to search in for file-ids.
356
314
    """
357
315
    # Get the old and new revision specs
358
316
    old_revision_spec = None
381
339
        default_location = path_list[0]
382
340
        other_paths = path_list[1:]
383
341
 
384
 
    def lock_tree_or_branch(wt, br):
385
 
        if wt is not None:
386
 
            wt.lock_read()
387
 
            add_cleanup(wt.unlock)
388
 
        elif br is not None:
389
 
            br.lock_read()
390
 
            add_cleanup(br.unlock)
391
 
 
392
342
    # Get the old location
393
343
    specific_files = []
394
344
    if old_url is None:
395
345
        old_url = default_location
396
346
    working_tree, branch, relpath = \
397
347
        bzrdir.BzrDir.open_containing_tree_or_branch(old_url)
398
 
    lock_tree_or_branch(working_tree, branch)
399
348
    if consider_relpath and relpath != '':
400
349
        if working_tree is not None and apply_view:
401
350
            views.check_path_in_view(working_tree, relpath)
409
358
    if new_url != old_url:
410
359
        working_tree, branch, relpath = \
411
360
            bzrdir.BzrDir.open_containing_tree_or_branch(new_url)
412
 
        lock_tree_or_branch(working_tree, branch)
413
361
        if consider_relpath and relpath != '':
414
362
            if working_tree is not None and apply_view:
415
363
                views.check_path_in_view(working_tree, relpath)
420
368
 
421
369
    # Get the specific files (all files is None, no files is [])
422
370
    if make_paths_wt_relative and working_tree is not None:
423
 
        other_paths = working_tree.safe_relpath_files(
424
 
            other_paths,
 
371
        try:
 
372
            from bzrlib.builtins import safe_relpath_files
 
373
            other_paths = safe_relpath_files(working_tree, other_paths,
425
374
            apply_view=apply_view)
 
375
        except errors.FileInWrongBranch:
 
376
            raise errors.BzrCommandError("Files are in different branches")
426
377
    specific_files.extend(other_paths)
427
378
    if len(specific_files) == 0:
428
379
        specific_files = None
460
411
                    old_label='a/', new_label='b/',
461
412
                    extra_trees=None,
462
413
                    path_encoding='utf8',
463
 
                    using=None,
464
 
                    format_cls=None):
 
414
                    using=None):
465
415
    """Show in text form the changes from one tree to another.
466
416
 
467
 
    :param to_file: The output stream.
468
 
    :param specific_files:Include only changes to these files - None for all
469
 
        changes.
470
 
    :param external_diff_options: If set, use an external GNU diff and pass 
471
 
        these options.
472
 
    :param extra_trees: If set, more Trees to use for looking up file ids
473
 
    :param path_encoding: If set, the path will be encoded as specified, 
474
 
        otherwise is supposed to be utf8
475
 
    :param format_cls: Formatter class (DiffTree subclass)
 
417
    to_file
 
418
        The output stream.
 
419
 
 
420
    specific_files
 
421
        Include only changes to these files - None for all changes.
 
422
 
 
423
    external_diff_options
 
424
        If set, use an external GNU diff and pass these options.
 
425
 
 
426
    extra_trees
 
427
        If set, more Trees to use for looking up file ids
 
428
 
 
429
    path_encoding
 
430
        If set, the path will be encoded as specified, otherwise is supposed
 
431
        to be utf8
476
432
    """
477
 
    if format_cls is None:
478
 
        format_cls = DiffTree
479
433
    old_tree.lock_read()
480
434
    try:
481
435
        if extra_trees is not None:
483
437
                tree.lock_read()
484
438
        new_tree.lock_read()
485
439
        try:
486
 
            differ = format_cls.from_trees_options(old_tree, new_tree, to_file,
487
 
                                                   path_encoding,
488
 
                                                   external_diff_options,
489
 
                                                   old_label, new_label, using)
 
440
            differ = DiffTree.from_trees_options(old_tree, new_tree, to_file,
 
441
                                                 path_encoding,
 
442
                                                 external_diff_options,
 
443
                                                 old_label, new_label, using)
490
444
            return differ.show_diff(specific_files, extra_trees)
491
445
        finally:
492
446
            new_tree.unlock()
703
657
        """
704
658
        def _get_text(tree, file_id, path):
705
659
            if file_id is not None:
706
 
                return tree.get_file_lines(file_id, path)
 
660
                return tree.get_file(file_id, path).readlines()
707
661
            else:
708
662
                return []
709
663
        try:
710
664
            from_text = _get_text(self.old_tree, from_file_id, from_path)
711
665
            to_text = _get_text(self.new_tree, to_file_id, to_path)
712
666
            self.text_differ(from_label, from_text, to_label, to_text,
713
 
                             self.to_file, path_encoding=self.path_encoding)
 
667
                             self.to_file)
714
668
        except errors.BinaryFile:
715
669
            self.to_file.write(
716
670
                  ("Binary files %s and %s differ\n" %
717
 
                  (from_label, to_label)).encode(self.path_encoding,'replace'))
 
671
                  (from_label, to_label)).encode(self.path_encoding))
718
672
        return self.CHANGED
719
673
 
720
674
 
736
690
                     path_encoding)
737
691
 
738
692
    @classmethod
739
 
    def make_from_diff_tree(klass, command_string, external_diff_options=None):
 
693
    def make_from_diff_tree(klass, command_string):
740
694
        def from_diff_tree(diff_tree):
741
 
            full_command_string = [command_string]
742
 
            if external_diff_options is not None:
743
 
                full_command_string += ' ' + external_diff_options
744
 
            return klass.from_string(full_command_string, diff_tree.old_tree,
 
695
            return klass.from_string(command_string, diff_tree.old_tree,
745
696
                                     diff_tree.new_tree, diff_tree.to_file)
746
697
        return from_diff_tree
747
698
 
797
748
                target.close()
798
749
        finally:
799
750
            source.close()
 
751
        if not allow_write:
 
752
            osutils.make_readonly(full_path)
800
753
        try:
801
754
            mtime = tree.get_file_mtime(file_id)
802
755
        except errors.FileTimestampUnavailable:
803
 
            pass
804
 
        else:
805
 
            os.utime(full_path, (mtime, mtime))
806
 
        if not allow_write:
807
 
            osutils.make_readonly(full_path)
 
756
            mtime = 0
 
757
        os.utime(full_path, (mtime, mtime))
808
758
        return full_path
809
759
 
810
760
    def _prepare_files(self, file_id, old_path, new_path, force_temp=False,
915
865
        :param using: Commandline to use to invoke an external diff tool
916
866
        """
917
867
        if using is not None:
918
 
            extra_factories = [DiffFromTool.make_from_diff_tree(using, external_diff_options)]
 
868
            extra_factories = [DiffFromTool.make_from_diff_tree(using)]
919
869
        else:
920
870
            extra_factories = []
921
871
        if external_diff_options:
922
872
            opts = external_diff_options.split()
923
 
            def diff_file(olab, olines, nlab, nlines, to_file, path_encoding=None):
924
 
                """:param path_encoding: not used but required
925
 
                        to match the signature of internal_diff.
926
 
                """
 
873
            def diff_file(olab, olines, nlab, nlines, to_file):
927
874
                external_diff(olab, olines, nlab, nlines, to_file, opts)
928
875
        else:
929
876
            diff_file = internal_diff
935
882
    def show_diff(self, specific_files, extra_trees=None):
936
883
        """Write tree diff to self.to_file
937
884
 
938
 
        :param specific_files: the specific files to compare (recursive)
 
885
        :param sepecific_files: the specific files to compare (recursive)
939
886
        :param extra_trees: extra trees to use for mapping paths to file_ids
940
887
        """
941
888
        try:
1031
978
            if error_path is None:
1032
979
                error_path = old_path
1033
980
            raise errors.NoDiffFound(error_path)
1034
 
 
1035
 
 
1036
 
format_registry = Registry()
1037
 
format_registry.register('default', DiffTree)