~bzr/ubuntu/lucid/bzr/beta-ppa

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2010-08-18 04:26:39 UTC
  • mfrom: (129.1.8 packaging-karmic)
  • Revision ID: mbp@sourcefrog.net-20100818042639-mjoxtngyjwiu05fo
* PPA rebuild for lucid.
* PPA rebuild for karmic.
* PPA rebuild onto jaunty.
* New upstream release.

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
21
20
import string
22
21
import sys
23
22
 
31
30
from bzrlib import (
32
31
    branch as _mod_branch,
33
32
    bzrdir,
34
 
    commands,
 
33
    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
    )
46
49
from bzrlib.symbol_versioning import (
47
50
    deprecated_function,
 
51
    deprecated_in,
48
52
    )
49
53
from bzrlib.trace import mutter, note, warning
50
54
 
95
99
    if sequence_matcher is None:
96
100
        sequence_matcher = patiencediff.PatienceSequenceMatcher
97
101
    ud = patiencediff.unified_diff(oldlines, newlines,
98
 
                      fromfile=old_filename.encode(path_encoding),
99
 
                      tofile=new_filename.encode(path_encoding),
 
102
                      fromfile=old_filename.encode(path_encoding, 'replace'),
 
103
                      tofile=new_filename.encode(path_encoding, 'replace'),
100
104
                      sequencematcher=sequence_matcher)
101
105
 
102
106
    ud = list(ud)
286
290
                        new_abspath, e)
287
291
 
288
292
 
 
293
@deprecated_function(deprecated_in((2, 2, 0)))
289
294
def get_trees_and_branches_to_diff(path_list, revision_specs, old_url, new_url,
290
295
                                   apply_view=True):
291
296
    """Get the trees and specific files to diff given a list of paths.
310
315
    :returns:
311
316
        a tuple of (old_tree, new_tree, old_branch, new_branch,
312
317
        specific_files, extra_trees) where extra_trees is a sequence of
313
 
        additional trees to search in for file-ids.
 
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.
314
356
    """
315
357
    # Get the old and new revision specs
316
358
    old_revision_spec = None
339
381
        default_location = path_list[0]
340
382
        other_paths = path_list[1:]
341
383
 
 
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
 
342
392
    # Get the old location
343
393
    specific_files = []
344
394
    if old_url is None:
345
395
        old_url = default_location
346
396
    working_tree, branch, relpath = \
347
397
        bzrdir.BzrDir.open_containing_tree_or_branch(old_url)
 
398
    lock_tree_or_branch(working_tree, branch)
348
399
    if consider_relpath and relpath != '':
349
400
        if working_tree is not None and apply_view:
350
401
            views.check_path_in_view(working_tree, relpath)
358
409
    if new_url != old_url:
359
410
        working_tree, branch, relpath = \
360
411
            bzrdir.BzrDir.open_containing_tree_or_branch(new_url)
 
412
        lock_tree_or_branch(working_tree, branch)
361
413
        if consider_relpath and relpath != '':
362
414
            if working_tree is not None and apply_view:
363
415
                views.check_path_in_view(working_tree, relpath)
411
463
                    old_label='a/', new_label='b/',
412
464
                    extra_trees=None,
413
465
                    path_encoding='utf8',
414
 
                    using=None):
 
466
                    using=None,
 
467
                    format_cls=None):
415
468
    """Show in text form the changes from one tree to another.
416
469
 
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
 
470
    :param to_file: The output stream.
 
471
    :param specific_files:Include only changes to these files - None for all
 
472
        changes.
 
473
    :param external_diff_options: If set, use an external GNU diff and pass 
 
474
        these options.
 
475
    :param extra_trees: If set, more Trees to use for looking up file ids
 
476
    :param path_encoding: If set, the path will be encoded as specified, 
 
477
        otherwise is supposed to be utf8
 
478
    :param format_cls: Formatter class (DiffTree subclass)
432
479
    """
 
480
    if format_cls is None:
 
481
        format_cls = DiffTree
433
482
    old_tree.lock_read()
434
483
    try:
435
484
        if extra_trees is not None:
437
486
                tree.lock_read()
438
487
        new_tree.lock_read()
439
488
        try:
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)
 
489
            differ = format_cls.from_trees_options(old_tree, new_tree, to_file,
 
490
                                                   path_encoding,
 
491
                                                   external_diff_options,
 
492
                                                   old_label, new_label, using)
444
493
            return differ.show_diff(specific_files, extra_trees)
445
494
        finally:
446
495
            new_tree.unlock()
657
706
        """
658
707
        def _get_text(tree, file_id, path):
659
708
            if file_id is not None:
660
 
                return tree.get_file(file_id, path).readlines()
 
709
                return tree.get_file_lines(file_id, path)
661
710
            else:
662
711
                return []
663
712
        try:
664
713
            from_text = _get_text(self.old_tree, from_file_id, from_path)
665
714
            to_text = _get_text(self.new_tree, to_file_id, to_path)
666
715
            self.text_differ(from_label, from_text, to_label, to_text,
667
 
                             self.to_file)
 
716
                             self.to_file, path_encoding=self.path_encoding)
668
717
        except errors.BinaryFile:
669
718
            self.to_file.write(
670
719
                  ("Binary files %s and %s differ\n" %
671
 
                  (from_label, to_label)).encode(self.path_encoding))
 
720
                  (from_label, to_label)).encode(self.path_encoding,'replace'))
672
721
        return self.CHANGED
673
722
 
674
723
 
683
732
    @classmethod
684
733
    def from_string(klass, command_string, old_tree, new_tree, to_file,
685
734
                    path_encoding='utf-8'):
686
 
        command_template = commands.shlex_split_unicode(command_string)
 
735
        command_template = cmdline.split(command_string)
687
736
        if '@' not in command_string:
688
737
            command_template.extend(['@old_path', '@new_path'])
689
738
        return klass(command_template, old_tree, new_tree, to_file,
748
797
                target.close()
749
798
        finally:
750
799
            source.close()
 
800
        try:
 
801
            mtime = tree.get_file_mtime(file_id)
 
802
        except errors.FileTimestampUnavailable:
 
803
            pass
 
804
        else:
 
805
            os.utime(full_path, (mtime, mtime))
751
806
        if not allow_write:
752
807
            osutils.make_readonly(full_path)
753
 
        try:
754
 
            mtime = tree.get_file_mtime(file_id)
755
 
        except errors.FileTimestampUnavailable:
756
 
            mtime = 0
757
 
        os.utime(full_path, (mtime, mtime))
758
808
        return full_path
759
809
 
760
810
    def _prepare_files(self, file_id, old_path, new_path, force_temp=False,
870
920
            extra_factories = []
871
921
        if external_diff_options:
872
922
            opts = external_diff_options.split()
873
 
            def diff_file(olab, olines, nlab, nlines, to_file):
 
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
                """
874
927
                external_diff(olab, olines, nlab, nlines, to_file, opts)
875
928
        else:
876
929
            diff_file = internal_diff
882
935
    def show_diff(self, specific_files, extra_trees=None):
883
936
        """Write tree diff to self.to_file
884
937
 
885
 
        :param sepecific_files: the specific files to compare (recursive)
 
938
        :param specific_files: the specific files to compare (recursive)
886
939
        :param extra_trees: extra trees to use for mapping paths to file_ids
887
940
        """
888
941
        try:
978
1031
            if error_path is None:
979
1032
                error_path = old_path
980
1033
            raise errors.NoDiffFound(error_path)
 
1034
 
 
1035
 
 
1036
format_registry = Registry()
 
1037
format_registry.register('default', DiffTree)